from typing import Optional, Dict
from typing_extensions import override

from buondua.models import Picture, Album, db
from buondua.scrappers.base import BaseParser


class PictureParser(BaseParser):
    '''Извлекает подробную информацию о альбоме и картинки'''

    @override
    def check_url(self, url) -> bool:
        return True

    def check_unique(self, album_url) -> bool:
        tmp = Album.select().where(Album.album_url == album_url)
        return len(tmp) < 1

    @override
    def save(self, data: Optional[Dict]):
        if not data:
            return
        album_data = data.pop('album')
        pictures_data = data.pop('pictures')
        with db.atomic():
            album_data['tags'] = b','.join(album_data['tags'])
            album = Album(**album_data)
            album.save()
            for picture in pictures_data:
                picture['album_id'] = album
                picture = Picture(**picture)
                picture.save()

    @override
    def extract(self) -> Optional[Dict]:
        url = self.extract_url()
        if not self.check_unique(url):
            return None
        title = self.extract_title()
        pages = self.extract_pages()
        images = [*self.extract_images()]
        tags = self.extract_tags()
        title_slug = self.generate_title_slug(title)
        for p in pages[1:]:
            self.document = self.get_document(p)
            images += self.extract_images()
        return {
            'album': {
                'album_url': url,
                'title': title,
                'title_slug': title_slug,
                'tags': tags
            },
            'pictures': [
                {
                    'url': v,
                    'pic_num': i + 1
                }
                for i, v in enumerate(images)
            ]
        }

    def extract_title(self):
        '''Возвращает заловок из тега og:title'''
        return self.document.find('meta', property='og:title')['content'].encode(self.DEFAULT_ENCODING)

    def extract_url(self):
        '''Возращает URL из тега og:url'''
        return self.document.find('meta', property='og:url')['content'].encode(self.DEFAULT_ENCODING)

    def extract_pages(self):
        '''Возвращает список URL-ов страниц альбома'''
        pagination_list = self.document.find('div', class_='pagination-list')
        link_tags = pagination_list.find_all('a') if pagination_list else []
        return [
            (self.BASE_URL + page).encode(self.DEFAULT_ENCODING)
            for page in map(
                lambda page: page['href'],
                link_tags
            )
        ]

    def extract_images(self):
        '''Возвращает список URL-ов картинок на странице'''
        return [
            page.encode(self.DEFAULT_ENCODING)
            for page in map(
                lambda page: page['src'],
                self.document.find('div', class_='article-fulltext').find_all('img')
            )
        ]

    def extract_tags(self):
        '''Возвращает список тегов (без решетки)'''
        return [
            tag.encode(self.DEFAULT_ENCODING)
            for tag in map(
                lambda tag: tag.text.strip('# '),
                self.document.find('div', class_='tags').find_all('span')
            )
        ]

    def generate_title_slug(self, title):
        '''Генерирует из title - slug'''
        from slugify import slugify
        return slugify(title).encode(self.DEFAULT_ENCODING)
